#ifndef __Y64_APIC_H__
#define __Y64_APIC_H__

#include "ptrace.h"

/*
    I/O APIC 中断向量号为32~55
        32  8259A
        33  keyboard
        34	HPET timer 0,8254 counter 0
        35	serial port A
        36	serial port B
        37	parallel port
        38	floppy
        39	parallel port
        40	RTC,HPET timer 1
        41	Generic
        42	Generic
        43	HPET timer 2
        44	HPET timer 3
        45	FERR#
        46	SATA primary
        47	SATA secondary
        48	PIRQA
        49	PIRQB
        50	PIRQC
        51	PIRQD
        52	PIRQE
        53	PIRQF
        54	PIRQG
        55	PIRQH 

    0x80		system call

    150 ~   200	Local APIC
        150	CMCI
        151	Timer
        152	Thermal Monitor
        153	Performance Counter
        154	LINT0
        155	LINT1
        156	Error

    200 ~   255	MP IPI
*/

// 投递模式
#define APIC_ICR_IOAPIC_FIXED           0
#define IOAPIC_ICR_LOWEST_PRIORITY      1
#define APIC_ICR_IOAPIC_SMI             2
#define APIC_ICR_IOAPIC_NMI             4
#define APIC_ICR_IOAPIC_INIT            5
#define ICR_START_UP                    6
#define IOAPIC_EXTINT                   7

// 投递目标
#define ICR_IOAPIC_DELV_PHYSICAL        0
#define ICR_IOAPIC_DELV_LOGICAL         1

// 投递状态
#define APIC_ICR_IOAPIC_IDLE            0
#define APIC_ICR_IOAPIC_SEND_PENDING    1

// 电平触发极性
#define APIC_IOAPIC_POLARITY_HIGH       0
#define APIC_IOAPIC_POLARITY_LOW        1

// 远程IRR
#define APIC_IOAPIC_IRR_RESET           0
#define APIC_IOAPIC_IRR_ACCEPT          1

// 触发模式
#define APIC_ICR_IOAPIC_EDGE            0
#define APIC_ICR_IOAPIC_LEVEL           1

// 屏蔽状态
#define APIC_ICR_IOAPIC_MASKED          1
#define APIC_ICR_IOAPIC_UN_MASKED       0

#define GET_IOAPIC_RTE_INDEX(irq) (((irq - 32) << 1) + 0x10)    // 第一个中断定向投递寄存器偏移地址为0x10, 0~31为系统使用中断向量号，一个中断两个中断定向投递寄存器

// I/O中断定向投递寄存器(RTE)，两个组成一个64位的中断项
typedef struct __attribute__((packed)) {
    unsigned int vector: 8;             // 0~7      中断向量号
    unsigned int deliver_mode: 3;       // 8~10     投递模式 000-fixed 001-Lowest Priority 010-SMI 100-NMI 101-INIT 111-ExtINT
    unsigned int dest_mode: 1;          // 11       目标模式 0-物理模式（使用APIC ID号来确定接收中断消息的处理器） 1-逻辑模式（使用LDR和DFR寄存器提供的自定义APIC ID号来确定接收中断消息的处理器）
    unsigned int deliver_status: 1;     // 12       投递状态 0-未产生中断或已投递且被受理 1-已投递但未被处理
    unsigned int polarity: 1;           // 13       电平触发极性 0-高电平触发 1-低电平触发
    unsigned int irr: 1;                // 14       远程IRR标志位，只在Fixed模式的电平触发模式下有效，在Local APIC处理中断请求时置位，在收到处理器发来的EOI命令时复位
    unsigned int trigger: 1;            // 15       触发模式 0-边沿触发 1-电平触发
    unsigned int mask: 1;               // 16       屏蔽标志位 0-未屏蔽 1-已屏蔽
    unsigned int reserved: 15;          // 17~31

    union {
        struct {
            unsigned int reserved1: 24; // 32~55
            unsigned int phy_dest: 4;   // 56~59    物理模式投递目标
            unsigned int reserved2: 4;  // 60~63
        } physical;
        struct {
            unsigned int reserved1: 24; // 32~55
            unsigned int logical_dest: 8;   //56~63 逻辑模式投递目标
        } logical;
    } destination;
} st_io_apic_rte_entry;

typedef struct {
    unsigned int phy_addr;              // 间接访问寄存器的物理地址
    unsigned char *vir_index_addr;      // 间接索引寄存器的映射线性地址
    unsigned int *vir_data_addr;        // 数据寄存器的映射线性地址
    unsigned int *vir_eoi_addr;         // EOI寄存器的映射线性地址
} st_io_apic_map;

extern st_io_apic_map g_ioapic_map;

void do_irq(st_pt_regs *regs, unsigned long nr);

void apic_ioapic_init();

void ioapic_init();

void io_apic_pagetable_remap();

void ioapic_enable(unsigned long irq);

void ioapic_disable(unsigned long irq);

unsigned long ioapic_install(unsigned long irq, void *arg);

void ioapic_uninstall(unsigned long irq);

void ioapic_level_ack(unsigned long irq);

void ioapic_edge_ack(unsigned long irq);

#endif
